home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Mania 6
/
MacMania 6.toast
/
/
Multimedia & Desktop
/
VideoToolbox
/
VideoToolboxSources
/
FlushCacheRange.c
< prev
next >
Wrap
Text File
|
1995-01-05
|
8KB
|
197 lines
/*
FlushCacheRange.c
A machine- and system-independent cache flush routine.
Beginning with the Macintosh II, developers were faced with situations where
instruction and/or data caches needed to be flushed for code to execute
correctly. Unfortunately, despite recent improvements (i.e. _HWPriv, see Tech
Note #261), cache flushing remains highly CPU- and system-specific and developers
have had difficulty doing it in a way that ensures both forward and backward
compatibility. FlushCacheRange.c contains a single function call that will work across
all platforms, yet still provides access to such advanced MC68040 features as
selective cache range flushing.
Dave Radcliffe Apple DTS January, 1992
****************************************************************************
HISTORY:
7/92 dgp This routine was distributed by Apple on their Developer Disk for May, 1992.
I changed the name of the file from Cache.c to FlushCacheRange.c, to match the
name of the routine itself, moved the prototype from Cache.h to VideoToolbox.h,
and pasted the contents of the "About..." file above. Otherwise the file is unchanged.
5/28/94 dgp Changed the type of unimpTrapAddress from long to
"UniversalProcPtr" in order to make this file compatible with Apple's Universal Headers.
1/5/95 dgp Made compatible with Universal Headers version 2.
NOTE: formerly FlushCodeCacheRange() returned an OSErr value, and FlushInstructionCache
was called if FlushCodeCacheRange failed. However, Apple's version 2 Universal Headers
declare FlushCodeCacheRange with no return value, so we can't check to see if it
failed. I haven't looked into Apple's documentation to see if there's another way
to check for failure.
****************************************************************************
*
* Cache control is a highly CPU specific function. Although some system independence
* is achieved via use of the _HWPriv trap, this solution may not be general for all
* hardware/system software combinations. FlushCacheRange should solve that for
* developers by working on all systems.
*
* Written by: Dave Radcliffe
*
* Copyright: © 1991 by Apple Computer, Inc., all rights reserved.
*
* Change History:
*
* 1/20/92 DR Added System603OrLater conditional code
* 1/10/92 DR Added FlushCacheWithCPushA()
* 12/18/91 DR New today
*
*/
#if __powerc
#error "This file cannot yet be compiled as PowerPC native code."
#else
#include "VideoToolbox.h" /* for prototype of FlushCacheRange */
#ifndef __TYPES__
#include <Types.h>
#endif
#ifndef __TRAPS__
#include <Traps.h>
#endif
#ifndef __OSUTILS__
#include <OSUtils.h>
#endif
#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
/*
* If you can guarantee you are running on System 6.0.3 or later, then some of the
* alternative cache flushing code implemented below is unnecessary as you are
* assured of having the _HWPriv trap. So, if you are running on System 6.0.3 or
* later, uncommenting the following line can reduce this code by more than half.
*/
/* #define System603OrLater */
/* The next two declarations are defined in Tech Note #261 */
#if !defined(_CacheFlush)
#define _CacheFlush 0xA0BD
#endif
#if UNIVERSAL_HEADERS<2
// changed by dgp to conform to Universal Headers version 2.
#pragma parameter FlushCodeCacheRange(__A0,__A1)
pascal void FlushCodeCacheRange (void *address, unsigned long count) =
{0x7009, 0xA098};
void FlushCodeCache (void) = _CacheFlush;
#endif
/*
* FlushCacheViaCACR is an inline assembly routine that flushes both the
* instruction and data caches by writing directly to the CACR. Used only
* as a last resort by FlushCacheRange
*/
void FlushCacheViaCACR ( void ) =
{ 0x4E7A, 0x0002, /* MOVEC CACR,D0 */
0x08C0, 0x0003, /* BSET #3,D0 */
0x4E7B, 0x0002 }; /* MOVEC D0,CACR */
/*
* FlushCacheWithCPushA is another inline assembly routine that flushes caches
* on the MC68040 using the CPushA instruction. Used only as a last resort
* by FlushCacheRange
*/
void FlushCacheWithCPushA ( void ) =
{ 0x4E71, /* NOP, to clear pending writes */
0xF4F8 }; /* CPUSHA BC */
/*
* FlushCacheRange flushes both the data and instruction caches for the block of
* memory starting at location address with size count. Flushing the cache for
* a range of memory is only supported on the 68040, so if this functionality is
* unavailable, the entire cache is flushed (if appropriate).
*
* If either address is NIL or count is zero, the entire cache is flushed anyway.
* Selective flushing of the cache is a time consuming process and you may wish to
* avoid it when there is no benefit to doing so. For example, if you've recently
* manipulated a block larger than 4K (the size of the 68040 caches), selective
* flushing will probably end up flushing the entire cache anyway, so why bother?
*
* The preferred method for flushing the cache is to use the _HWPriv trap documented
* in Tech Note #261. Some older systems may not have this trap implemented, so
* alternate methods must be used. The first thing to try is the _CacheFlush trap.
* This was implemented beginning with the Mac II (and is also documented in Tech
* Note #261).
*
* MC68000 based systems have no cache, but if an accelerator board has been added.
* they may have a CPU which does have a cache. Accelerator board vendors should
* implement _HWPriv or _CacheFlush for such systems, but if they haven't then
* our last resort is to control the caches directly (using privileged
* instructions (GAK!!)).
*
* FINALLY, the full implementation of FlushCacheRange is probably overkill and may be
* less than optimal for some applications. For example, testing for _HWPriv
* should be unnecessary on systems later than 6.0.2, so I've added conditional code
* to allow you to bypass that if appropriate (see comment above on System603OrLater).
* The full implementation tries to cover a lot of obscure cases, but it also does
* some things inefficiently. For example, having determined that _HWPriv is
* implemented, it would be more efficient to just keep that information around,
* but I wanted to avoid the complications of global or static variables. But
* it is also true that if you find it necessary to call this code more than a
* few times between the time your application starts and the time it quits,
* YOU ARE DOING SOMETHING WRONG!! Go back and rethink your code.
*/
void FlushCacheRange (void *address, unsigned long count)
{
#ifndef System603OrLater
long gestaltResponse; /* For CPU type */
#if defined(USESROUTINEDESCRIPTORS)
UniversalProcPtr unimpTrapAddress; /* Address of Unimplemented Trap */
#else
long unimpTrapAddress; /* Address of Unimplemented Trap */
#endif
/* First check to see if _HWPriv is implemented */
if ((unimpTrapAddress = NGetTrapAddress(_Unimplemented, ToolTrap)) !=
NGetTrapAddress(_HWPriv, OSTrap)) {
#endif
/*
* Try to flush the specified range. If it fails or if there is no range,
* then flush the entire cache
*/
if (address==NULL || count==0)FlushInstructionCache();/* Flush entire cache */
else FlushCodeCacheRange(address,count);
/*
NOTE: formerly FlushCodeCacheRange() returned an OSErr value, and FlushInstructionCache
was called if FlushCodeCacheRange failed. However, the version 2 Universal Headers
declare FlushCodeCacheRange with no return value, so we can't check to see if it
failed. I haven't looked into Apple's documentation to see if there's another way
to check for failure. dgp 1/5/95
*/
#ifndef System603OrLater
} else { /* No _HWPriv trap */
/* Try for _CacheFlush trap */
if (unimpTrapAddress != NGetTrapAddress(_CacheFlush, OSTrap))
FlushCodeCache ();
else /* Nothing else works, so do machine specific cache control */
/* Only bother with cache control on 68020 and above */
if (!Gestalt (gestaltProcessorType, &gestaltResponse) &&
(gestaltResponse >= gestalt68020))
if (gestaltResponse <= gestalt68030)
FlushCacheViaCACR ();
else
FlushCacheWithCPushA ();
}
#endif
return;
} /* FlushCacheRange */
#endif